using Circus.CodeEditor;
using Circus.CodeEditor.Serialization;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Circus.CodeEditor
{
	public class Margin : IDisposable
	{
		private Pen pen;
		private Pen columnPen;
		private int position = EditConsts.DefaultMarginPosition;
		private int[] columnPositions = new int[]
		{
			EditConsts.DefaultColumnMarginPosition
		};
		private bool visible;
		private bool columnsVisible;
		private bool allowDrag;
		private bool showHints;
		private bool isDragging;
		private CodeEditor owner;
		private int drawX = -1;
		private int drawY = -1;
		private int updateCount;
		
		[Description("Gets or sets value indicating position, in characters, of the vertical line within the text portion of the control.")]
		public virtual int Position
		{
			get
			{
				return this.position;
			}
			set
			{
				if (this.position != value)
				{
					this.position = value;
					this.OnPositionChanged();
				}
			}
		}
		[Description("Gets or sets the character columns where additional column margin will be drawn.")]
		public virtual int[] ColumnPositions
		{
			get
			{
				return this.columnPositions;
			}
			set
			{
				if (this.columnPositions != value)
				{
					this.columnPositions = new int[value.Length];
					Array.Copy(value, this.columnPositions, value.Length);
					int num = 0;
					int[] array = this.columnPositions;
					for (int i = 0; i < array.Length; i++)
					{
						int num2 = array[i];
						if (num2 <= num)
						{
							ErrorHandler.Error(new Exception(string.Format(StringConsts.InvalidMarginColumn, value.ToString())));
						}
						num = num2;
					}
					this.OnColumnPositionsChanged();
				}
			}
		}
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public virtual Pen Pen
		{
			get
			{
				return this.pen;
			}
			set
			{
				if (this.pen != value)
				{
					this.pen = value;
					this.OnPenChanged();
				}
			}
		}
		[Description("Gets or sets a color of the margin line.")]
		public virtual Color PenColor
		{
			get
			{
				return this.pen.Color;
			}
			set
			{
				if (this.pen.Color != value)
				{
					this.pen.Color = value;
					this.OnPenColorChanged();
				}
			}
		}
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public virtual Pen ColumnPen
		{
			get
			{
				return this.columnPen;
			}
			set
			{
				if (this.columnPen != value)
				{
					this.columnPen = value;
					this.OnColumnPenChanged();
				}
			}
		}
		[Description("Gets or sets a color of the column margin line.")]
		public virtual Color ColumnPenColor
		{
			get
			{
				return this.columnPen.Color;
			}
			set
			{
				if (this.columnPen.Color != value)
				{
					this.columnPen.Color = value;
					this.OnColumnPenColorChanged();
				}
			}
		}
		[DefaultValue(false), Description("Gets or sets a value indicating whether vertical line should be painted.")]
		public virtual bool Visible
		{
			get
			{
				return this.visible;
			}
			set
			{
				if (this.visible != value)
				{
					this.visible = value;
					this.OnVisibleChanged();
				}
			}
		}
		[DefaultValue(false), Description("Gets or sets a value indicating whether column margins should be painted.")]
		public virtual bool ColumnsVisible
		{
			get
			{
				return this.columnsVisible;
			}
			set
			{
				if (this.columnsVisible != value)
				{
					this.columnsVisible = value;
					this.OnColumnsVisibleChanged();
				}
			}
		}
		[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public virtual bool IsDragging
		{
			get
			{
				return this.isDragging;
			}
			set
			{
				if (this.isDragging != value)
				{
					this.isDragging = value;
					this.OnIsDragingChanged();
				}
			}
		}
		[DefaultValue(false), Description("Indicates whether drag operation can performed to \"Margin\".")]
		public virtual bool AllowDrag
		{
			get
			{
				return this.allowDrag;
			}
			set
			{
				if (this.allowDrag != value)
				{
					this.allowDrag = value;
					this.OnAllowDrawChanged();
				}
			}
		}
		[DefaultValue(false), Description("Gets or sets a value indicating whether \"Margin\" should display some hint when mouse pointer is over the margin area.")]
		public virtual bool ShowHints
		{
			get
			{
				return this.showHints;
			}
			set
			{
				if (this.showHints != value)
				{
					this.showHints = value;
					this.OnShowHintsChanged();
				}
			}
		}
		
		protected void DrawLine(int x, int y, bool erase)
		{
			this.drawX = x;
			this.drawY = y;
			if (this.owner != null)
			{
				CodeEditor syntaxEdit = this.owner;
				Rectangle clientRect;
				
				{
					clientRect = syntaxEdit.ClientRect;
				}
				if (erase)
				{
					syntaxEdit.Invalidate(new Rectangle(x, clientRect.Top, 1, clientRect.Height));
				}
				else
				{
					Graphics graphics = syntaxEdit.CreateGraphics();
					try
					{
						graphics.DrawLine(this.pen, x, clientRect.Top, x, clientRect.Bottom);
					}
					finally
					{
						graphics.Dispose();
					}
				}
			}
		}
		protected int GetColumnPosition(int pos)
		{
			int num = this.columnPositions.Length;
			int result;
			if (num == 0)
			{
				result = EditConsts.DefaultColumnMarginPosition;
			}
			else
			{
				int num2 = pos - this.columnPositions[num - 1];
				if (num2 >= 0)
				{
					int num3;
					if (num == 1)
					{
						num3 = this.columnPositions[0];
					}
					else
					{
						num3 = this.columnPositions[num - 1] - this.columnPositions[num - 2];
					}
					result = this.columnPositions[num - 1] + (num2 / num3 + 1) * num3;
				}
				else
				{
					int num3 = 0;
					while (pos >= this.columnPositions[num3])
					{
						num3++;
					}
					result = this.columnPositions[num3];
				}
			}
			return result;
		}
		protected virtual void OnColumnPositionsChanged()
		{
		}
		protected virtual void OnPenColorChanged()
		{
		}
		protected virtual void OnColumnPenColorChanged()
		{
		}
		protected virtual void OnIsDragingChanged()
		{
			if (this.drawX >= 0)
			{
				this.DrawLine(this.drawX, this.drawY, true);
			}
			this.owner.Invalidate();
			this.drawX = -1;
			this.drawY = -1;
		}
		protected virtual void OnAllowDrawChanged()
		{
		}
		protected virtual void OnShowHintsChanged()
		{
		}
		protected virtual void OnPositionChanged()
		{
			this.Update(true);
		}
		protected virtual void OnPenChanged()
		{
			this.Update();
		}
		protected virtual void OnColumnPenChanged()
		{
			this.Update();
		}
		protected virtual void OnVisibleChanged()
		{
			this.Update();
		}
		protected virtual void OnColumnsVisibleChanged()
		{
			this.Update();
		}
		public Margin()
		{
			this.pen = new Pen(EditConsts.DefaultMarginForeColor, 1f);
			this.columnPen = new Pen(EditConsts.DefaultMarginColumnForeColor, 1f);
			this.columnPen.DashStyle = DashStyle.Dot;
		}
		public Margin(CodeEditor owner) : this()
		{
			this.owner = owner;
		}
		~Margin()
		{
			this.Dispose(false);
		}
		public bool ShouldSerializePosition()
		{
			return this.position != EditConsts.DefaultMarginPosition;
		}
		public bool ShouldSerializeColumnPositions()
		{
			return this.columnPositions.Length != 1 || this.columnPositions[0] != EditConsts.DefaultColumnMarginPosition;
		}
		public bool ShouldSerializePenColor()
		{
			return this.PenColor != EditConsts.DefaultMarginForeColor;
		}
		public bool ShouldSerializeColumnPenColor()
		{
			return this.ColumnPenColor != EditConsts.DefaultMarginColumnForeColor;
		}
		public virtual int BeginUpdate()
		{
			this.updateCount++;
			return this.updateCount;
		}
		public virtual int EndUpdate()
		{
			this.updateCount--;
			if (this.updateCount == 0)
			{
				this.Update();
			}
			return this.updateCount;
		}
		public virtual int DisableUpdate()
		{
			this.updateCount++;
			return this.updateCount;
		}
		public virtual int EnableUpdate()
		{
			this.updateCount--;
			return this.updateCount;
		}
		public void Update(bool needUpdate)
		{
			if (this.updateCount == 0 && this.owner != null)
			{
				this.owner.Invalidate();
				if (needUpdate && this.owner.WordWrap && this.owner.WrapAtMargin)
				{
					this.owner.UpdateWordWrap();
				}
			}
		}
		public void Update()
		{
			if (this.updateCount == 0 && this.owner != null)
			{
				this.owner.Invalidate();
			}
		}
		public virtual void Assign(Margin source)
		{
			this.BeginUpdate();
			try
			{
				this.Pen.Width = source.Pen.Width;
				this.Pen.Color = source.Pen.Color;
				this.ColumnPen.Width = source.ColumnPen.Width;
				this.ColumnPen.Color = source.ColumnPen.Color;
				this.Position = source.Position;
				this.ColumnPositions = source.ColumnPositions;
				this.Visible = source.Visible;
				this.ColumnsVisible = source.ColumnsVisible;
				this.AllowDrag = source.AllowDrag;
				this.ShowHints = source.ShowHints;
			}
			finally
			{
				this.EndUpdate();
			}
		}
		public virtual void Paint(Painter painter, Rectangle rect)
		{
			if (!this.isDragging)
			{
				painter.DrawLine(rect.Left, 0, rect.Left, rect.Bottom, this.pen.Color, (int)this.pen.Width, this.pen.DashStyle);
			}
		}
		public virtual void PaintColumn(Painter painter, Rectangle rect)
		{
			if (this.columnPen.DashStyle == DashStyle.Dot)
			{
				painter.DrawDotLine(rect.Left, 0, rect.Left, rect.Bottom, this.columnPen.Color, Color.Empty);
			}
			else
			{
				painter.DrawLine(rect.Left, 0, rect.Left, rect.Bottom, this.columnPen.Color, (int)this.columnPen.Width, this.columnPen.DashStyle);
			}
		}
		public virtual void ResetPosition()
		{
			this.Position = EditConsts.DefaultMarginPosition;
		}
		public virtual void ResetColumnPositions()
		{
			this.ColumnPositions = new int[]
			{
				EditConsts.DefaultColumnMarginPosition
			};
		}
		public virtual void ResetPenColor()
		{
			this.PenColor = EditConsts.DefaultMarginForeColor;
		}
		public virtual void ResetVisible()
		{
			this.Visible = false;
		}
		public virtual void ResetColumnsPenColor()
		{
			this.PenColor = EditConsts.DefaultMarginColumnForeColor;
		}
		public virtual void ResetColumnsVisible()
		{
			this.ColumnsVisible = false;
		}
		public virtual void ResetAllowDrag()
		{
			this.AllowDrag = false;
		}
		public virtual void ResetShowHints()
		{
			this.ShowHints = false;
		}
		public virtual void CancelDragging()
		{
			this.IsDragging = false;
		}
		public virtual bool Contains(int x, int y)
		{
			bool result;
			if (this.owner != null)
			{
				Point point = this.owner.ScreenToDisplay(x, y);
				int x2 = this.owner.DisplayToScreen(this.Position, point.Y, true).X;
				result = (x > x2 - EditConsts.DefaultRulerHitWidth && x <= x2 + EditConsts.DefaultRulerHitWidth);
			}
			else
			{
				result = false;
			}
			return result;
		}
		public virtual void DragTo(int x, int y)
		{
			if (this.drawX >= 0)
			{
				this.DrawLine(this.drawX, this.drawY, true);
			}
			this.DrawLine(x, y, false);
		}
		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				if (this.pen != null)
				{
					this.pen.Dispose();
					this.pen = null;
				}
				if (this.columnPen != null)
				{
					this.columnPen.Dispose();
					this.columnPen = null;
				}
			}
		}
		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}
	}
}
